package com.xpec.c4.h5net;

import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.netty.bootstrap.Bootstrap;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.channel.UpstreamMessageEvent;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor;

import com.ms.service.module.analysis.PlatformType;
import com.xpec.c4.codec.CodecUtility;
import com.xpec.c4.game.login.LoginModule;
import com.xpec.c4.game.login.db.LoginDAO;
import com.xpec.c4.game.time.TimeConstants;
import com.xpec.c4.game.utility.GUID;
import com.xpec.c4.game.utility.GUIDFactory;
import com.xpec.c4.game.utility.GUIDType;
import com.xpec.c4.game.utility.GameUtility;
import com.xpec.c4.message.ConstantCode;
import com.xpec.c4.message.MessageTypes;
import com.xpec.c4.message.login.CAccountLoginRequest;
import com.xpec.c4.message.login.CAccountRobotLoginRequest;
import com.xpec.c4.message.login.SAccountLoginRequest;
import com.xpec.c4.net.XSENetConstant;
import com.xpec.c4.net.handler.ConsolidatingAutoFlusher;
import com.xpec.c4.service.contexts.Contexts;
import com.xpec.c4.service.group.ServerGroup;
import com.xpec.c4.service.group.transportlayer.GroupMessage;
import com.xpec.c4.service.h5common.H5ServiceInfo;
import com.xpec.c4.service.h5server.H5ServerOperations;
import com.xpec.c4.service.message.NetMessage;
import com.xpec.c4.service.module.ConsistentGroupName;
import com.xpec.c4.service.module.ServerProperties;
import com.xpec.c4.service.module.gateway.CGatewayCodeRequest;
import com.xpec.c4.service.server.CloseType;
import com.xpec.net.xnetty.h5cihper.H5BaseCipherChannelHandler;
import com.xpec.net.xnetty.h5cihper.H5ServerCipherChannelHandler;

public class H5XSENetNettyServer extends H5XSENetServer {
	/**
	 * 登入時的 gateway code 保留時間
	 */
	public static final int DELAYMAXTIME = (int) (5 * TimeConstants.MILLI_SECOND_PRE_MINUTE); // 5分鐘內需登入

	/**
	 * 
	 */
	private Bootstrap mBootstrap;

	/**
	 * 
	 */
	protected Channel mChannel = null;

	/**
	 * 當前連線數, 非線上玩家數量
	 */
	private AtomicInteger connectCount = new AtomicInteger(0);

	/**
	 * 當前機器人連線數
	 */
	private AtomicInteger robotConnectCount = new AtomicInteger(0);

	/**
	 * 總歷史連線數
	 */
	private AtomicInteger historyConnectCount = new AtomicInteger(0);

	public H5XSENetNettyServer(int protocolType) {
		if (protocolType == XSENetConstant.PROTOCOLTYPE_TCP) {
			int processorNum = Runtime.getRuntime().availableProcessors();

			mBootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(
					Executors.newCachedThreadPool(),
					new OrderedMemoryAwareThreadPoolExecutor(2 * processorNum,
							0, 0)));
		}
	}

	public void setHandleMode(int mode) {
		if (mode == XSENetConstant.HANDLE_GATEWAYMODE)
			mBootstrap.setPipelineFactory(new H5XSENetGatewayPipelineFactory(
					name, this));
	}

	public void start() {
		long bufSize = 1 << 20;
		long childBufSize = 1 << 20;

		// / TCP server
		mBootstrap.setOption("child.tcpNoDelay", true); // / 關閉 Nagle演算法
		mBootstrap.setOption("child.keepAlive", true);
		mBootstrap.setOption("child.sendBufferSize", childBufSize);
		mBootstrap.setOption("child.receiveBufferSize", childBufSize);
		mBootstrap.setOption("child.backlog", 1024);

		mBootstrap.setOption("tcpNoDelay", true);
		mBootstrap.setOption("broadcast", false);
		mBootstrap.setOption("sendBufferSize", bufSize);
		mBootstrap.setOption("receiveBufferSize", bufSize);
		mBootstrap.setOption("backlog", 1024);

		// / TCP server 除了這個 server channel, 每個 client 連進來就會開一個新的
		// / client channel (child channel)
		mChannel = ((ServerBootstrap) mBootstrap).bind(mAddress);

	}

	public void close() {
		mChannel.close().awaitUninterruptibly();
	}

	public boolean isStarted() {
		return mChannel.isOpen();
	}

	public void incrementOnlineUser() {
		connectCount.incrementAndGet();
		historyConnectCount.incrementAndGet();
	}

	public void decrementOnlineUser() {
		connectCount.decrementAndGet();
	}

	/**
	 * 增加機器人連線數量
	 */
	public void incrementOnlineRobot() {
		robotConnectCount.incrementAndGet();
	}

	/**
	 * 減少機器人連線數量
	 */
	public void decrementOnlineRobot() {
		robotConnectCount.decrementAndGet();
	}

	public int getConnectCount() {
		return connectCount.get();
	}

	public int getHistoryConnectCount() {
		return historyConnectCount.get();
	}

	public int getRobotCount() {
		return robotConnectCount.get();
	}

	private H5XSENetSpeedometerFilter meter = new H5XSENetSpeedometerFilter();

	public H5XSENetSpeedometerFilter getMeter() {
		return meter;
	}

}

/*********************************************************************
 * 
 * 
 *
 */
class H5XSENetGatewayPipelineFactory implements ChannelPipelineFactory {
	/**
	 * 是否使用计速器？
	 */
	private static final boolean enableSpeedFilter = ServerProperties
			.getBoolean("speedfilter", false);

	/**
	 * 是否使用消息加密？
	 */
	private static final boolean enableUseCipher = ServerProperties.getBoolean(
			"useCipher", false);

	/**
	 * 是否為騰訊TGW接入
	 */
	private static final boolean enableTGWHandler = ServerProperties
			.getBoolean("useTGWHandler", false);

	private H5XSENetNettyServer parent = null;

	/**
	 * module name
	 */
	private String name;

	public H5XSENetGatewayPipelineFactory(String name,
			H5XSENetNettyServer parent) {
		this.name = name;
		this.parent = parent;
	}

	@Override
	public ChannelPipeline getPipeline() throws Exception {
		ChannelPipeline p = Channels.pipeline();

		if (!enableUseCipher) {
			p.addLast(ConsolidatingAutoFlusher.class.getSimpleName(),
					new ConsolidatingAutoFlusher());
		}

		// //rowan
		// p.addLast(XSENetSwfSecurityHandler.class.getSimpleName(), new
		// XSENetSwfSecurityHandler());

		// 是否為騰訊TGW接入
		// if(enableTGWHandler)
		// {
		// p.addLast(XSENetTGWHandler.class.getSimpleName(), new
		// XSENetTGWHandler());
		// }

		// 是否使用流量统计？
		if (enableSpeedFilter) {
			p.addLast(H5XSENetSpeedometerFilter.class.getSimpleName(),
					parent.getMeter());
		}

		// 是否使用消息加密？
		if (enableUseCipher) {
			p.addLast(H5BaseCipherChannelHandler.class.getSimpleName(),
					new H5ServerCipherChannelHandler());
		}

		p.addLast(H5XSENetNettyDecoder.class.getSimpleName(),
				new H5XSENetNettyDecoder());
		p.addLast(H5XSENetNettyEncoder.class.getSimpleName(),
				new H5XSENetNettyEncoder());
		p.addLast(H5XSENetLoginVerifyHandler.class.getSimpleName(),
				new H5XSENetLoginVerifyHandler(name, parent));

		// / 處理我們自己訊息的一定是最後一個 addLast 的
		p.addLast(H5XSENetGatewayChannelHandler.class.getSimpleName(),
				new H5XSENetGatewayChannelHandler(name, parent));

		return p;
	}

}

/**
 * 
 *
 */
class H5XSENetGatewayChannelHandler extends SimpleChannelHandler {
	private static final Log log = LogFactory
			.getLog(H5XSENetGatewayChannelHandler.class);

	private H5XSENetNettyServer parent = null;

	/**
	 * module name
	 */
	private String name;

	private String mAccountID;

	public void setAccountID(String id) {
		mAccountID = id;
	}

	public H5XSENetGatewayChannelHandler(String name, H5XSENetNettyServer parent) {
		super();
		this.name = name;
		this.parent = parent;
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
		Throwable ex = e.getCause();
		if (!(ex instanceof ClosedChannelException)) {
			if (log.isErrorEnabled()) {
				// log.error(ctx, e.getCause());
				log.error(e);
			}
		}
		e.getChannel().close();
	}

	@Override
	public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
		Object message = e.getMessage();
		if (message == null) {
			if (log.isErrorEnabled()) {
				log.error("message = null, channel=" + ctx.getChannel().getId());
			}
			return;
		}

		if (!(message instanceof NetMessage)) {
			if (log.isErrorEnabled()) {
				log.error("message is not instance of NetMessage, class=" + message.getClass().getName()
						+ " channel=" + ctx.getChannel().getId());
			}
			return;
		}

		NetMessage msg = (NetMessage) message;

		int messageType = msg.getMessageType();

		if (messageType != 111019) {
			if (log.isInfoEnabled()) {
				log.info("recv message " + messageType + " "
						+ ConstantCode.getName(MessageTypes.class, messageType) + " from channel "
						+ ctx.getChannel().getId());
			}
		}

		// client送出字首为4的message表示不合法
		if (messageType / 100000 == 4) {
			if (log.isErrorEnabled()) {
				log.error("wrong message type " + messageType + " from client:" + e.toString() + " channel="
						+ ctx.getChannel().getId());
			}
			return;
		}

		GUID sessionID = H5XSENetSessionPool.getSession(ctx.getChannel())
				.getID();

		if (sessionID == null) {
			if (log.isErrorEnabled()) {
				log.error("sessionID = null, channel=" + ctx.getChannel().getId());
			}
			return;
		}

		byte[] messageContentBytes = msg.getMessageContentBytes();
		String moduleID = msg.getModuleID();

		// 将client送来的twork Message转送给对应的Module
		GroupMessage gm = new GroupMessage();
		gm.setDestModuleID(moduleID);
		gm.setSessionID(sessionID);
		gm.setMessageType(messageType);
		gm.setMessageContentBytes(messageContentBytes);

		ServerGroup.getTransportManager().sendMessage(gm);
		ctx.sendUpstream(e);
	}

	/**
	 * Invoked when a Channel is open, but not bound nor connected.
	 */
	@Override
	public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) {
		ctx.sendUpstream(e);
	}

	/**
	 * Invoked when a Channel is open and bound to a local address, but not
	 * connected.
	 */
	@Override
	public void channelBound(ChannelHandlerContext ctx, ChannelStateEvent e) {
		ctx.sendUpstream(e);
	}

	/**
	 * Invoked when a Channel was closed and all its related resources were
	 * released.
	 */
	@Override
	public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) {
		ctx.sendUpstream(e);
	}

	/**
	 * Invoked when a Channel is open, bound to a local address and connected to
	 * a remote address.
	 */
	@Override
	public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
		this.parent.incrementOnlineUser();

		if (log.isInfoEnabled()) {
			log.info(GameUtility.getCurMethodName() + ": channel "
					+ e.getChannel().getId());
		}

		try {
			/**
			 * session ID 改成 swf 驗證完畢後再做
			 */
			ctx.sendUpstream(e);

			// channel要先記下來, 不然強迫斷線時不到人~
			H5XSENetSessionPool.addSession(e.getChannel(), null);
		} catch (Exception ex) {
			if (log.isErrorEnabled()) {
				log.error(GameUtility.getCurMethodName() + ": Exception", ex);
			}
		}
	}

	/**
	 * Invoked when a Channel was disconnected from its remote peer.
	 */
	@Override
	public void channelDisconnected(ChannelHandlerContext ctx,
			ChannelStateEvent e) {
		this.parent.decrementOnlineUser();

		ctx.sendUpstream(e);

		Channel ch = e.getChannel();

		if (log.isInfoEnabled()) {
			log.info(GameUtility.getCurMethodName() + ": channel " + ch.getId());
		}

		GUID sessionID;
		try {
			H5XSENetSession xseSession = H5XSENetSessionPool.getSession(ch);

			if (xseSession != null) {
				sessionID = xseSession.getID();

				if (sessionID != null) {

					CloseType closeType = H5ServerOperations
							.getSessionCloseType(xseSession);

					// 斷現處理流程
					H5ServerOperations.disconnectionLocalProcess(sessionID,
							closeType, parent.h5GatewayModule);

					parent.h5GatewayModule.removeSession(sessionID);
				} else {
					// sessionID = null
					// 有建立連線，但沒有走到帳號登入就不會有 sessionID
					if (log.isErrorEnabled()) {
						log.error(GameUtility.getCurMethodName()
								+ ": session GUID not found from xseSession in channel "
								+ ch.getId());
					}
				}

				boolean isRobot = (boolean) xseSession.getParameters().get(
						H5ServerOperations.IS_ROBOT);
				if (isRobot) {
					this.parent.decrementOnlineRobot();
				}

				if (log.isInfoEnabled()) {
					log.info(GameUtility.getCurMethodName() + ": channel "
							+ ch.getId() + " s:" + sessionID
							+ " disconnect proc finish.");
				}
			} else {
				// xseSession = null
				// 有建立連線，但沒有走到帳號登入就不會有 xseSession

				H5ServiceInfo.removeSession(xseSession);

				if (log.isErrorEnabled()) {
					log.error(GameUtility.getCurMethodName()
							+ ": xseSession not found by channel " + ch.getId());
				}
			}
			H5XSENetSessionPool.removeSession(ch);
		} catch (RuntimeException ex) {
			if (log.isErrorEnabled()) {
				log.error(
						GameUtility.getCurMethodName() + ": RuntimeException",
						ex);
			}
		} catch (Exception ex) {
			if (log.isErrorEnabled()) {
				log.error(GameUtility.getCurMethodName() + ": Exception", ex);
			}
		}

		// log.info(sessionID + " is closed!");
	}

}

class H5XSENetNettyEncoder extends OneToOneEncoder {
	private static final Log log = LogFactory
			.getLog(H5XSENetNettyEncoder.class);

	private static final short START_FLAG = Short.MAX_VALUE;

	@Override
	protected Object encode(ChannelHandlerContext ctx, Channel channel,
			Object obj) throws Exception {
		if (!channel.isConnected())
			return obj;

		// / 跟 bytebuffer 非相關的東西就不 encode
		if (!(obj instanceof ByteBuffer)) {
			return obj;
		}

		ByteBuffer message = (ByteBuffer) obj;

		return ChannelBuffers.wrappedBuffer(message);
	}

}

class H5XSENetSwfSecurityHandler extends SimpleChannelHandler {
	private static String responseXML = "<cross-domain-policy> <allow-access-from domain=\"*\" to-ports=\"*\"/></cross-domain-policy> \0";

	private boolean first = true;

	@Override
	public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
			throws Exception {
		if (first) {
			first = false;

			ChannelBuffer channelBuffer = (ChannelBuffer) e.getMessage();

			String value = new String(channelBuffer.array());
			if (value.startsWith("<policy-file-request/>")) {
				Channel channel = e.getChannel();

				ChannelBuffer buffer = ChannelBuffers.buffer(responseXML
						.getBytes().length);
				buffer.writeBytes(responseXML.getBytes());

				channel.write(buffer);

				// 强制马上刷新发送
				ConsolidatingAutoFlusher flusher = (ConsolidatingAutoFlusher) channel
						.getPipeline().get("ConsolidatingAutoFlusher");
				if (flusher != null) {
					// rowan:
					// flusher.flush();
				}

				channel.getPipeline().remove("H5XSENetSwfSecurityHandler");
				return;
			} else {
				first = true;
			}
		}
		ctx.sendUpstream(e);
	}

}

class H5XSENetLoginVerifyHandler extends SimpleChannelHandler {
	private static final Log log = LogFactory
			.getLog(H5XSENetLoginVerifyHandler.class);

	private boolean first = true;

	private String name;

	private H5XSENetServer server = null;

	public H5XSENetLoginVerifyHandler(String name, H5XSENetServer _server) {
		super();
		this.name = name;
		this.server = _server;
	}

	@Override
	public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
			throws Exception {
		// rowan:no new incomer
		if (false == server.isNewConnectionAllowed()) {
			Channel channel = e.getChannel();
			channel.close();
			first = false;
		}

		if (first) {
			first = false;

			Object message = e.getMessage();
			if (message != null && message instanceof NetMessage) {
				NetMessage msg = (NetMessage) message;

				int messageType = msg.getMessageType();
				if (messageType == MessageTypes.C_ACCOUNT_LOGIN_REQUEST) {
					// TODO kevin jb verify
					if (log.isInfoEnabled()) {
						log.info(LoginModule.LOGIN_TRACE_LOG_STRING
								+ " recieve [C_ACCOUNT_LOGIN_REQUEST], msg: "
								+ msg);
					}
					// gateway 收到 client 的登入要求
					// 若是帳號登入, 則將帳號重新指定
					try {
						// 收到client第一个有效的Message后再开始建立 session id 和后续的对应数据
						Channel ch = e.getChannel();
						// String sessionID;
						//
						// sessionID = name + "#"
						// + DataTransfer.createSessionID(ch);

						// 產生 sessionID
						GUID sessionID = GUIDFactory
								.createUUID(GUIDType.TYPE_SESSION);

						if (log.isInfoEnabled()) {
							log.info(LoginModule.LOGIN_TRACE_LOG_STRING
									+ " Generate sessionID: " + sessionID);
						}

						H5XSENetSession newSession = new H5XSENetSession(ch);
						newSession.setID(sessionID);
						H5XSENetSessionPool.addSession(ch, newSession);

						if (log.isInfoEnabled()) {
							log.info("create xseSession with channel="
									+ ch.getId() + " sessionId=" + sessionID);
						}

						// 這是供全域使用
						H5ServiceInfo.addSession(sessionID, newSession);
						// 單獨記一份在自己的Gateway內
						server.h5GatewayModule
								.addSession(sessionID, newSession);

						byte[] messageContentBytes = msg
								.getMessageContentBytes();

						CAccountLoginRequest reqClient = (CAccountLoginRequest) CodecUtility
								.decodeByte(messageContentBytes);

						// 識別 client 是否為機器人
						boolean isRobot = false;
						if (reqClient instanceof CAccountRobotLoginRequest) {
							CAccountRobotLoginRequest reqRobot = (CAccountRobotLoginRequest) reqClient;
							if (reqRobot.isRobot()) {
								isRobot = true;
							}
						}

						if (!isRobot) { // 不是機器人的話
							// 判斷是否能登入
							try {
								// 版本 => ver-XXX
								String loginPlatform = reqClient.loginPlatForm;
								PlatformType platformType = PlatformType
										.getENUMbyString(loginPlatform);
								if (platformType == PlatformType.H5_MOBILE
										|| platformType == PlatformType.H5_WINDOWS) {
								} else {
									if (log.isInfoEnabled()) {
										log.info(LoginModule.LOGIN_TRACE_LOG_STRING
												+ " Not H5 Login : "
												+ loginPlatform);
									}
									first = true;
									Channel channel = e.getChannel();
									channel.close();
									return;
								}
							} catch (Exception ee) {
								first = true;
								Channel channel = e.getChannel();
								channel.close();
								return;
							}
						}

						// get gateway code from redis
						CGatewayCodeRequest verifyData = LoginDAO
								.getGatewayCodeFromRedis(reqClient.code);

						String agentData = "";
						if (verifyData != null) {
							agentData = verifyData.agentData;
						}

						Contexts.startSessionContextMessage(sessionID, name, reqClient.clientIp,
								reqClient.loginPlatForm, agentData);

						newSession.getParameters().put(
								H5ServerOperations.IS_ROBOT, isRobot);

						// 增加機器人連線數量
						if (isRobot) {
							if (server instanceof H5XSENetNettyServer) {
								H5XSENetNettyServer nettyServer = (H5XSENetNettyServer) server;
								nettyServer.incrementOnlineRobot();
							}
						}

						if (log.isInfoEnabled()) {
							log.info("client login request: login="
									+ reqClient.login + " code="
									+ reqClient.code + " token="
									+ reqClient.reconnectToken);
						}

						if (verifyData != null) {
							if (log.isInfoEnabled()) {
								log.info(LoginModule.LOGIN_TRACE_LOG_STRING
										+ " "
										+ server.getH5gatewayModule()
												.getModuleName()
										+ " a: "
										+ verifyData.account
										+ " check verifyCode from client, verifyCode: "
										+ verifyData.code);
							}
						}

						// String loginModule = ConsistentGroupName.lookUp(
						// ModuleName.GROUP_LOGIN, verifyData.account);

						SAccountLoginRequest reqServer = new SAccountLoginRequest();

						// 找不到verifyData, 可能是透過f5刷新, 丟到login去做檢查好了
						if (verifyData == null) {
							if (log.isWarnEnabled()) {
								log.warn("VerifyCode is null! "
										+ reqClient.code);
							}
							if (GameUtility
									.isHaveString(reqClient.reconnectToken)) {
								reqServer.account = null;
								reqServer.code = reqClient.code;
								reqServer.reconnectToken = reqClient.reconnectToken;
								reqServer.playerIp = reqClient.clientIp;

								messageContentBytes = CodecUtility.encodeByte(
										reqServer,
										MessageTypes.S_ACCOUNT_LOGIN_REQUEST);
								msg = new NetMessage();
								msg.setSessionID(sessionID);
								msg.setMessageContentBytes(messageContentBytes);
								msg.setMessageType(MessageTypes.S_ACCOUNT_LOGIN_REQUEST);
								msg.setModuleID(reqClient.login);
								e.getChannel().getPipeline()
										.remove("H5XSENetLoginVerifyHandler");
								ctx.sendUpstream(new UpstreamMessageEvent(e
										.getChannel(), msg, e
										.getRemoteAddress()));
								return;
							}
						} else if (verifyData.time
								+ H5XSENetNettyServer.DELAYMAXTIME >= System
									.currentTimeMillis()) {
							// verifyData 還沒有過期

							// 找出 account id 對應的 login module
							String loginModule = ConsistentGroupName
									.lookUpLoginModule(verifyData.account,
											verifyData.robot);

							reqServer.account = verifyData.account;
							reqServer.code = reqClient.code;
							reqServer.playerIp = reqClient.clientIp;

							messageContentBytes = CodecUtility.encodeByte(
									reqServer,
									MessageTypes.S_ACCOUNT_LOGIN_REQUEST);
							msg = new NetMessage();
							msg.setSessionID(sessionID);
							msg.setMessageContentBytes(messageContentBytes);
							msg.setMessageType(MessageTypes.S_ACCOUNT_LOGIN_REQUEST);
							msg.setModuleID(loginModule);
							e.getChannel().getPipeline()
									.remove("H5XSENetLoginVerifyHandler");
							ctx.sendUpstream(e);
							ctx.sendUpstream(new UpstreamMessageEvent(e
									.getChannel(), msg, e.getRemoteAddress()));
							return;
						} else {
							if (log.isWarnEnabled()) {
								log.warn("VerifyCode is timeout! time:"
										+ verifyData.time + " now:"
										+ System.currentTimeMillis());
							}
						}

						if (log.isWarnEnabled()) {
							log.warn("client login with invalid-code and disconnect : "
									+ reqClient.code);
						}
						// verifyData 還沒有過期

						// if
						// (reqClient.reconnectToken.equals("e12078eb30ddab72ceb74750167186b29167c21a"))
						// {
						// reqServer.account =
						// GUID.parseUUID("0010240c591aad12e7e22fc7");
						// }
						// 找出 account id 對應的 login module
						// String loginModule = ConsistentGroupName
						// .lookUpLoginModule(reqServer.account,
						// false);
						//
						// reqServer.code = reqClient.code;
						// reqServer.playerIp = reqClient.clientIp;
						//
						// messageContentBytes = CodecUtility
						// .encodeByte(reqServer,
						// MessageTypes.S_ACCOUNT_LOGIN_REQUEST);
						// msg = new NetMessage();
						// msg.setSessionID(sessionID);
						// msg.setMessageContentBytes(messageContentBytes);
						// msg.setMessageType(MessageTypes.S_ACCOUNT_LOGIN_REQUEST);
						// msg.setModuleID(loginModule);
						// e.getChannel().getPipeline()
						// .remove("H5XSENetLoginVerifyHandler");
						// ctx.sendUpstream(e);
						// ctx.sendUpstream(new UpstreamMessageEvent(e
						// .getChannel(), msg, e.getRemoteAddress()));
						// return;

					} catch (Exception ex) {
						if (log.isErrorEnabled()) {
							log.error("C_ACCOUNT_LOGIN_REQUEST fail", ex);
						}
					}
				}
			}
		}

		// rowan: not know why this?
		// 非法連線
		first = true;
		Channel channel = e.getChannel();
		channel.close();

		return;
	}
	
}
